﻿using System;
using System.Collections.Generic;
using System.ServiceModel;
using System.Threading;
using ClimateControl.Infrastructure;
using Microsoft.Practices.Prism.Commands;
using ClimateControl.Infrastructure.Service;
using ClimateControl.Manager.Properties;
using log4net;
using System.Windows.Threading;

namespace ClimateControl.Manager.ViewModel
{
    class MainViewModel : BaseViewModel, IDisposable
    {
        #region Fields

        ClimateManager client;
        private DispatcherTimer reconnectTimer;
        private static readonly ILog log = LogManager.GetLogger(typeof(MainViewModel));

        #endregion Fields

        #region Properties

        private State _state;
        public State State
        {
            get { return _state; }
            private set { SetAndNotify(ref _state, value); }
        }

        public int _temperature;
        public int Temperature
        {
            get { return _temperature; }
            set { SetAndNotify(ref _temperature, value); }
        }

        public bool _isAirConOn;
        public bool IsAirConOn
        {
            get { return _isAirConOn; }
            set
            {
                SetAndNotify(ref _isAirConOn, value);
                new Thread(() => client.SetIsAirConOn(_isAirConOn)).Start();
            }
        }

        private int _voteExpiry;
        public int VoteExpiry
        {
            get { return _voteExpiry; }
            set { SetAndNotify(ref _voteExpiry, value); }
        }

        private double _voteFrequency;
        public double VoteFrequency
        {
            get { return _voteFrequency; }
            set { SetAndNotify(ref _voteFrequency, value); }
        }

        public bool _isBigFanOn;
        public bool IsBigFanOn
        {
            get { return _isBigFanOn; }
            set
            {
                SetAndNotify(ref _isBigFanOn, value);
                new Thread(() => client.SetIsBigFanOn(_isBigFanOn)).Start();
            }
        }

        private int _updateFrequency;
        public int UpdateFrequency
        {
            get { return _updateFrequency; }
            set { SetAndNotify(ref _updateFrequency, value); }
        }

        #endregion Properties

        #region Commands

        private DelegateCommand _resetCommand;
        public DelegateCommand ResetCommand
        {
            get { return _resetCommand;  }
            private set { SetAndNotify(ref _resetCommand, value); }
        }

        private DelegateCommand _setTemperatureCommand;
        public DelegateCommand SetTemperatureCommand
        {
            get { return _setTemperatureCommand; }
            private set { SetAndNotify(ref _setTemperatureCommand, value); }
        }

        private DelegateCommand _setVoteExpiryCommand;
        public DelegateCommand SetVoteExpiryCommand
        {
            get { return _setVoteExpiryCommand; }
            private set { SetAndNotify(ref _setVoteExpiryCommand, value); }
        }

        private DelegateCommand _setVoteFrequencyCommand;
        public DelegateCommand SetVoteFrequencyCommand
        {
            get { return _setVoteFrequencyCommand; }
            private set { SetAndNotify(ref _setVoteFrequencyCommand, value); }
        }

        private DelegateCommand _setUpdateFrequencyCommand;
        public DelegateCommand SetUpdateFrequencyCommand
        {
            get { return _setUpdateFrequencyCommand; }
            private set { SetAndNotify(ref _setUpdateFrequencyCommand, value); }
        }

        #endregion Commands

        #region Constructor

        public MainViewModel()
        {
            reconnectTimer = new DispatcherTimer();
            reconnectTimer.Interval = TimeSpan.FromSeconds(10);
            reconnectTimer.Tick += (s, e) => StartBackgroundThread(OpenService);

            StartBackgroundThread(OpenService);

            ResetCommand = new DelegateCommand(() => StartBackgroundThread(client.ResetVotes));
            SetTemperatureCommand = new DelegateCommand(() => StartBackgroundThread(() => client.SetTemperature(Temperature)));
            SetVoteExpiryCommand = new DelegateCommand(() => StartBackgroundThread(() => client.SetVoteExpiry(VoteExpiry)));
            SetVoteFrequencyCommand = new DelegateCommand(() => StartBackgroundThread(() => client.SetVoteFrequency(VoteFrequency)));
            SetUpdateFrequencyCommand = new DelegateCommand(() => StartBackgroundThread(() => client.SetUpdateFrequency(UpdateFrequency)));
        }

        #endregion Constructor

        #region Methods

        private void OpenService()
        {
            try
            {
                reconnectTimer.Stop();

                State = State.Connecting;

                client = new ClimateManager(TryReconnect, Settings.Default.ServiceLocation);

                ClimateInfo climateInfo = client.GetClimateInfo();
                Temperature = climateInfo.Temperature;
                IsAirConOn = climateInfo.IsAirConOn;
                VoteExpiry = climateInfo.VoteExpiry;
                VoteFrequency = climateInfo.VoteFrequency;
                UpdateFrequency = climateInfo.UpdateFrequency;

                State = State.Ready;
            }
            catch (Exception ex)
            {
                log.Error(ex.Message);
                TryReconnect();
            }
        }

        private void TryReconnect(object sender = null, EventArgs e = null)
        {
            if (!reconnectTimer.IsEnabled)
            {
                reconnectTimer.Start();
            }
        }

        #endregion Methods

        #region IDiposable

        public void Dispose()
        {
            State = State.ShuttingDown;
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (client != null)
                {
                    try
                    {
                        client.Close();
                    }
                    catch (Exception)
                    {
                        client.Abort();
                    }
                    client = null;
                }
            }
        }

        #endregion
    }
}
